home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DDJ0992.ARJ / UNLOAD.C < prev    next >
C/C++ Source or Header  |  1992-05-19  |  10KB  |  327 lines

  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // UNLOAD.C        Copyright (c) 1992 by Mike Sax
  4. //
  5. // Unload is a small programmer's utility that lets you remove any program
  6. // or DLL that is stuck in memory.
  7. //
  8. ////////////////////////////////////////////////////////////////////////////
  9. #define STRICT 1
  10. #include <windows.h>
  11. #include <string.h>
  12. #include <toolhelp.h>
  13. #include "unload.h"
  14.  
  15. // Global variables:
  16. static HINSTANCE ghInstance;
  17.  
  18. // Exported functions:
  19. BOOL FAR PASCAL _export MainDlgProc(HWND hDlg, unsigned message, WORD wParam,
  20.                                     LONG lParam);
  21. BOOL FAR PASCAL _export WarningDlgProc(HWND hDlg, WORD wMessage, WORD wParam,
  22.                                        LONG lParam);
  23. BOOL FAR PASCAL _export EnumTaskWindowsFunc(HWND hWnd, DWORD lParam);
  24.  
  25. // Internal functions:
  26. void static FillupComboBox(HANDLE hComboBox);
  27. void static ShowItemInfo(HWND hDlg, HWND hComboBox);
  28. void static KillTask(HTASK hTask, int nMethod);
  29. BOOL static IsDLL(HMODULE hModule);
  30.  
  31. // The WinMain function is called at the beginning of our program
  32. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  33.                    LPSTR lpCmdLine, int nCmdShow)
  34.     {
  35.     ghInstance = hInstance;
  36.  
  37.     (void)lpCmdLine;
  38.     if (!hPrevInstance)
  39.         {
  40.         WNDCLASS  wc;
  41.  
  42.         // Register private dialog class
  43.         wc.style = 0l;
  44.         wc.lpfnWndProc = DefDlgProc;
  45.         wc.cbClsExtra = 0;
  46.         wc.cbWndExtra = DLGWINDOWEXTRA;
  47.         wc.hInstance = ghInstance;
  48.         wc.hIcon = LoadIcon(hInstance, "Unload");
  49.         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  50.         wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  51.         wc.lpszMenuName =  NULL;
  52.         wc.lpszClassName = "Unload";
  53.         if (!RegisterClass(&wc))
  54.             return -1;
  55.         }
  56.     // Use a dialog box as our main window and pass the nCmdShow parameter
  57.     // in lParam of MainDlgProc's WM_INITDIALOG.
  58.     return DialogBoxParam(ghInstance, "Unload", NULL, (DLGPROC)
  59.                 MakeProcInstance((FARPROC)MainDlgProc, ghInstance),
  60.                 (LONG)nCmdShow);
  61.     // Proc Instance will be automatically cleaned up by Windows.
  62.     }
  63.  
  64. // MainDlgProc handles all messages for our main window.
  65. BOOL FAR PASCAL _export MainDlgProc(HWND hDlg, unsigned message, WORD wParam,
  66.                                     LONG lParam)
  67.     {
  68.     switch (message)
  69.         {
  70.         case WM_INITDIALOG:
  71.             // We passed the nCmdShow parameter of WinMain in lParam
  72.             ShowWindow(hDlg, LOWORD(lParam));
  73.             break;
  74.         case WM_CLOSE:
  75.             EndDialog(hDlg, FALSE);
  76.             break;
  77.         case WM_COMMAND:
  78.             switch(wParam)
  79.                 {
  80.                 // Combo box notification message
  81.                 case IDD_COMBOBOX:
  82.                     if (HIWORD(lParam) == CBN_DROPDOWN)
  83.                         FillupComboBox((HANDLE)LOWORD(lParam));
  84.                     else if (HIWORD(lParam) == CBN_SELCHANGE)
  85.                         {
  86.                         static BOOL bFirst = TRUE;
  87.  
  88.                         if (bFirst)
  89.                             {
  90.                             SetDlgItemText(hDlg, IDD_MESSAGE, "Compuserve: 75470,1403");
  91.                             bFirst = FALSE;
  92.                             }
  93.                         ShowItemInfo(hDlg, (HANDLE)LOWORD(lParam));
  94.                         }
  95.                     break;
  96.                 // User pressed the "Unload" button
  97.                 case IDD_UNLOAD:
  98.                     {
  99.                     FARPROC lpProc;
  100.                     int nCurSel = (int)SendDlgItemMessage(hDlg, IDD_COMBOBOX,
  101.                                     CB_GETCURSEL, 0, 0l);
  102.                     // If no item selected, do nothing
  103.                     if (nCurSel == CB_ERR)
  104.                         {
  105.                         MessageBeep(0);
  106.                         break;
  107.                         }
  108.                     lpProc = MakeProcInstance((FARPROC)WarningDlgProc,
  109.                              ghInstance);
  110.                     // Call "Unload" dialog box and pass the module handle
  111.                     // in lParam of WarningDlgProc's WM_INITDIALOG
  112.                     if (DialogBoxParam(ghInstance, "WARNING", hDlg,
  113.                         (DLGPROC)lpProc, SendDlgItemMessage(hDlg,
  114.                             IDD_COMBOBOX, CB_GETITEMDATA, nCurSel, 0l)))
  115.                         {
  116.                         // Give Windows a chance to process the WM_QUIT
  117.                         // or WM_CLOSE messages we might have posted
  118.                         Yield();
  119.                         FillupComboBox(GetDlgItem(hDlg, IDD_COMBOBOX));
  120.                         }
  121.                     FreeProcInstance(lpProc);
  122.                     }
  123.                 }
  124.             break;
  125.         default:
  126.             return FALSE;        // We did not process the message
  127.         }
  128.     return TRUE;                // We processed the message
  129.     }
  130.  
  131. // FillupComboBox fills up the combo box with a list of all modules
  132. // that are currently loaded.  Every item in the list box also contains
  133. // a "long" data item (attached using CB_SETITEMDATA) that is a combination
  134. // of the module handle and the usage count.
  135. void static FillupComboBox(HANDLE hComboBox)
  136.     {
  137.     int nIndex;
  138.     BOOL bSucces;
  139.     HMODULE hSelectedModule;
  140.     MODULEENTRY ModuleEntry;
  141.  
  142.     // Keep the module handle of the item that is currently selected
  143.     nIndex = SendMessage(hComboBox, CB_GETCURSEL, 0, 0l);
  144.     hSelectedModule = (HMODULE) ((CB_ERR == nIndex) ? -1 :
  145.             HIWORD(SendMessage(hComboBox, CB_GETITEMDATA, nIndex, 0l)));
  146.     SendMessage(hComboBox, CB_RESETCONTENT, 0, 0l);
  147.     ModuleEntry.dwSize = sizeof (MODULEENTRY);
  148.     bSucces = ModuleFirst(&ModuleEntry);
  149.     while(bSucces)
  150.         {
  151.         if (IsDLL(ModuleEntry.hModule))
  152.             AnsiLower(ModuleEntry.szModule);
  153.         nIndex = (int)SendMessage(hComboBox, CB_ADDSTRING, 0,
  154.                                   (LONG) (LPSTR) ModuleEntry.szModule);
  155.         if ((nIndex != CB_ERR) && (nIndex != CB_ERRSPACE))
  156.             {
  157.             SendMessage(hComboBox, CB_SETITEMDATA, nIndex,
  158.                         MAKELONG(ModuleEntry.wcUsage, ModuleEntry.hModule));
  159.             bSucces = ModuleNext(&ModuleEntry);
  160.             }
  161.         else
  162.             bSucces = FALSE;
  163.         }
  164.     // Check if the previously selected module is still in the list and
  165.     // if so, reselect it.
  166.     for (nIndex = SendMessage(hComboBox, CB_GETCOUNT, 0, 0l) - 1;
  167.          nIndex >= 0 ; --nIndex)
  168.          if ((HMODULE) HIWORD(SendMessage(hComboBox, CB_GETITEMDATA,
  169.              nIndex, 0)) == hSelectedModule)
  170.              {
  171.              SendMessage(hComboBox, CB_SETCURSEL, nIndex, 0l);
  172.              break;
  173.              }
  174.     ShowItemInfo(GetParent(hComboBox), hComboBox);
  175.     }
  176.  
  177. // Show information about the currently selected item in the combo box.
  178. void static ShowItemInfo(HWND hDlg, HWND hComboBox)
  179.     {
  180.     int nCurSel;
  181.  
  182.     nCurSel = (int)SendMessage(hComboBox, CB_GETCURSEL, 0, 0l);
  183.     if (CB_ERR == nCurSel)
  184.         {
  185.         SetDlgItemText(hDlg, IDD_FILENAME, "");
  186.         SetDlgItemText(hDlg, IDD_MODULE, "");
  187.         SetDlgItemText(hDlg, IDD_KIND, "");
  188.         SetDlgItemText(hDlg, IDD_USAGE, "");
  189.         EnableWindow(GetDlgItem(hDlg, IDD_UNLOAD), FALSE);
  190.         }
  191.     else
  192.         {
  193.         char szScrap[MAX_PATH + 1];
  194.         char *pcFilename;
  195.         DWORD dwData;
  196.  
  197.         dwData = SendMessage(hComboBox, CB_GETITEMDATA, nCurSel, 0l);
  198.         GetModuleFileName((HMODULE)HIWORD(dwData), szScrap, MAX_PATH);
  199.         // Remove the path from the filename
  200.         pcFilename = strrchr(szScrap, '\\');
  201.         pcFilename = (pcFilename == NULL) ? szScrap : pcFilename + 1;
  202.         SetDlgItemText(hDlg, IDD_KIND, (IsDLL((HMODULE)HIWORD(dwData)) ?
  203.                                         "Library" : "Program"));
  204.         SetDlgItemText(hDlg, IDD_FILENAME, pcFilename);
  205.         SetDlgItemInt(hDlg, IDD_USAGE, LOWORD(dwData), FALSE);
  206.         wsprintf(szScrap, "%04x", HIWORD(dwData));
  207.         SetDlgItemText(hDlg, IDD_MODULE, (LPSTR) szScrap);
  208.         EnableWindow(GetDlgItem(hDlg, IDD_UNLOAD), LOWORD(dwData));
  209.         }
  210.     }
  211.  
  212. // When the user pressed the Unload button, the "warning dialog" appears
  213. BOOL FAR PASCAL _export WarningDlgProc(HWND hDlg, WORD wMessage, WORD wParam,
  214.                                        LONG lParam)
  215.     {
  216.     static HMODULE hModule; // Only one dialog can be active!
  217.  
  218.     switch(wMessage)
  219.         {
  220.         case WM_INITDIALOG:
  221.             // The handle of the module to be freed is in the hiword
  222.             // of lParam, passed on using DialogBoxParam.  Since we
  223.             // use the same dialog box for both programs and libraries,
  224.             // we have to adjust our dialog a little, depending on the
  225.             // type of dialog.
  226.             if (IsDLL((HMODULE)HIWORD(lParam)))
  227.                 {
  228.                 EnableWindow(GetDlgItem(hDlg, IDD_TERMINATE), FALSE);
  229.                 EnableWindow(GetDlgItem(hDlg, IDD_DESTROY), FALSE);
  230.                 }
  231.             else
  232.                 SetDlgItemText(hDlg, IDD_REFERENCEZERO,
  233.                                "Post WM_QUIT message");
  234.             CheckDlgButton(hDlg, IDD_REFERENCEZERO, 1);
  235.             hModule = (HMODULE)HIWORD(lParam);
  236.             break;
  237.         case WM_COMMAND:
  238.             switch(wParam)
  239.                 {
  240.                 case IDOK:
  241.                     {
  242.                     if (IsDLL(hModule))
  243.                         {
  244.                         int nUsage = GetModuleUsage(hModule);
  245.                         while (nUsage--)
  246.                             FreeLibrary(hModule);
  247.                         }
  248.                     else
  249.                         {
  250.                         BOOL bSucces;
  251.                         TASKENTRY TaskEntry;
  252.                         int nMethod =
  253.                         (IsDlgButtonChecked(hDlg, IDD_REFERENCEZERO)) ? 0 :
  254.                         (IsDlgButtonChecked(hDlg, IDD_TERMINATE)) ? 1 : 2;
  255.  
  256.                         TaskEntry.dwSize = sizeof(TASKENTRY);
  257.                         bSucces = TaskFirst(&TaskEntry);
  258.                         while(bSucces)
  259.                             {
  260.                             if (TaskEntry.hModule == hModule)
  261.                                 KillTask(TaskEntry.hTask, nMethod);
  262.                             bSucces = TaskNext(&TaskEntry);
  263.                             }
  264.                         }
  265.                     EndDialog(hDlg, TRUE);
  266.                     }
  267.                     break;
  268.                 case IDCANCEL:
  269.                     EndDialog(hDlg, FALSE);
  270.                     break;
  271.                 }
  272.             break;
  273.         case WM_CLOSE:
  274.             EndDialog(hDlg, FALSE);
  275.             break;
  276.         default:
  277.             return FALSE;
  278.         }
  279.     return TRUE;
  280.     }
  281.  
  282. // KillTask kills a task using a method of your choice.  It is called
  283. // from the "Warning" dialog box when the user presses Ok.
  284. void static KillTask(HTASK hTask, int nMethod)
  285.     {
  286.     switch(nMethod)
  287.         {
  288.         case 0:     // Post WM_QUIT message
  289.             PostAppMessage(hTask, WM_QUIT, 0, 0l);
  290.             break;
  291.         case 1:     // Terminate application
  292.             TerminateApp(hTask, NO_UAE_BOX);
  293.             break;
  294.         case 2:     // Close all the task's windows
  295.             {
  296.             FARPROC lpProc = MakeProcInstance((FARPROC)EnumTaskWindowsFunc,
  297.                                               ghInstance);
  298.             EnumTaskWindows(hTask,(WNDENUMPROC)lpProc, 0l);
  299.             FreeProcInstance(lpProc);
  300.             }
  301.             break;
  302.         }
  303.     }
  304.  
  305. // EnumTaskWindowsFunc is called for every toplevel window that belongs to
  306. // a task.  It simply posts a WM_CLOSE message to this window.
  307. BOOL FAR PASCAL _export EnumTaskWindowsFunc(HWND hWnd, DWORD lParam)
  308.     {
  309.     (void)lParam;                        // Avoid compiler warnings
  310.     if (GetParent(hWnd) == NULL)
  311.         PostMessage(hWnd, WM_CLOSE, 0, 0l);
  312.     return TRUE;
  313.     }
  314.  
  315. // IsDLL returns TRUE if the specified module is a Dynamic Link Library, or
  316. // FALSE if it is a program.
  317. BOOL static IsDLL(HMODULE hModule)
  318.     {
  319.     int i;
  320.  
  321.     // The module handle is really the selector of a far pointer to
  322.     // the new-style .EXE header of the module.  The bit at 0x8000 of
  323.     // the word at offset 0xC in this structure is set if it's a DLL.
  324.     MemoryRead((WORD)hModule, 0xCl, &i, sizeof(i));
  325.     return (i & 0x8000) ? TRUE : FALSE;
  326.     }
  327.